package com.jcl.core.security.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.userdetails.UserDetails;

import java.io.InputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName JwtTokenUtil
 * @Author yyliu
 * @Date 2018/12/18 11:35
 * @Version 1.0
 **/
public class JwtTokenUtil {

    private static final Logger logger = LoggerFactory.getLogger(JwtTokenUtil.class);

    private static final long serialVersionUID = -3301605591108950415L;

    private static final String CLAIM_KEY_USERNAME = "sub";
    private static final String CLAIM_KEY_CREATED = "created";

    // 30分钟
    public static final Integer EXPIRATION = 1800;

    // 寻找证书文件
    private static String fileName = "jwt.jks";
    private static String JKS = "JKS";
    private static String password = "JCL123456!";
    private static String alias = "certificatekey";
    private static InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName); // 寻找证书文件
    private static PrivateKey privateKey = null;
    private static PublicKey publicKey = null;

    static { // 将证书文件里边的私钥公钥拿出来
        try {
            KeyStore keyStore = KeyStore.getInstance(JKS); // java key store 固定常量
            keyStore.load(inputStream, password.toCharArray());
            privateKey = (PrivateKey) keyStore.getKey(alias, password.toCharArray()); // jwt 为 命令生成整数文件时的别名
            publicKey = keyStore.getCertificate(alias).getPublicKey();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成token
     *
     * @param userDetails           （主体信息）
     * @return
     */
    public static String generateToken(UserDetails userDetails) {
        Map<String, Object> claims = new HashMap<>();
        claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
        claims.put(CLAIM_KEY_CREATED, new Date());
        return generateToken(claims);
    }

    /**
     * 生成token
     *
     * @param subject           （主体信息）
     * @param expirationSeconds 过期时间（秒）
     * @return
     */
    public static String generateToken(String subject, int expirationSeconds) {
        Map<String, Object> claims = new HashMap<>();
        claims.put(CLAIM_KEY_USERNAME, subject);
        claims.put(CLAIM_KEY_CREATED, new Date());
        return generateToken(subject, expirationSeconds, claims);
    }

    /**
     * 生成token
     *
     * @param subject           （主体信息）
     * @param expirationSeconds 过期时间（秒）
     * @param claims            自定义身份信息
     * @return
     */
    public static String generateToken(String subject, int expirationSeconds, Map<String, Object> claims) {
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(subject)
                .setExpiration(new Date(System.currentTimeMillis() + expirationSeconds * 1000))
                .signWith(SignatureAlgorithm.RS256, privateKey)
                .compact();
    }

    public static String refreshToken(String token){
        String refreshedToken = null;
        try {
            Claims claims = generateTokenClaims(token);
            claims.put("created", new Date());
            refreshedToken = generateToken(claims);
        } catch (Exception e) {
            refreshedToken = null;
        }
        return refreshedToken;
    }
   /* *
    * @Author yyliu
    * @Description 解析token 获取 subject
    * @Date 14:54 2018/12/18
    * @Param [token, salt]
    * @return java.lang.String
    **/
    public static String getSubject(String token) {
        String subject = null;
        try {
            Claims claims = generateTokenClaims(token);
            subject = claims.getSubject();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return subject;
    }

    public static Map<String, Object> getClaims(String token) {
        Map<String, Object> claims = null;
        try {
            claims = generateTokenClaims(token);
        } catch (Exception e) {

        }
        return claims;
    }

    /* *
     * @Author yyliu
     * @Description 是否过期
     * @Date 14:53 2018/12/18
     * @Param [token]
     * @return boolean
     **/
    public static boolean isExpiration(String token) {
        return generateTokenClaims(token).getExpiration().before(new Date());
    }

    private static String generateToken(Map<String, Object> claims) {
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(generateExpirationDate())
                .signWith(SignatureAlgorithm.RS256, privateKey)
                .compact();
    }

    private static Claims generateTokenClaims(String token) {
        return Jwts.parser()
                .setSigningKey(publicKey)
                .parseClaimsJws(token)
                .getBody();
    }

    private static Date generateExpirationDate() {
        return new Date(System.currentTimeMillis() + EXPIRATION * 1000);
    }

    public static void main(String[] args) {
        // String token = generateToken("dddddd", 1500);
        String token = "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJsY0BqdWNhaWxpbi5jb20iLCJjcmVhdGVkIjoxNTQ1MzA3MjU2ODE2LCJleHAiOjE1NDUzMDcyODl9.U51nij_6EoafVpItRrzWb2X7ZyFJ-YWaE1PYX6t26YrAuNQ-wQB9mbg0S1XegqVQZy5B82uG_3pUQy0XPNzUDtnww58H7rNIsnw6hYmogx6QCXSTALZUUMaQ5UzrmlJz_H6j5ECdu2KvBahuT2jlf6d9DWfSvdMg0Icp1DXjgZWaHMT4xEaysv-2co2jw6qRQq5C7atH4yZzQ2g7RK1j4Po5nyMNSr33mhHX174rj8v6Upyron6F0dhRyWweYgoyUovHmBFC46mXoo-HNZNQtPwy-iC49HMDxKJB54L4aLn7GAH9J0RREYeHxER21A3m3uaFh9S4eNGJLyOuYVNjMw";
        System.out.println(token);
        System.out.println(getSubject(token));
    }

}
